/**
 * 值动画
 * 目前仅支持线性动画
 * @author slc
 */
class ValueAnim {
    //动画执行id
    _intervalTaskId
    //动画帧率
    _frameRate = 1000 / 60
    //总份数
    _servingCount
    //每一份大小
    _servingSize
    //当前份数下标
    _currentServeIndex
    //动画时长
    duration
    //动画开始值
    startValue
    //动画结束值
    endValue

    //监听更新函数
    onUpdate
    //监听开始函数
    onStart
    //监听结束函数
    onEnd
    //监听取消函数
    onCancel

    constructor(duration = 1000, startValue = 0, endValue = 1) {
        this.duration = duration
        this.startValue = startValue
        this.endValue = endValue
    }

    /**
     * 获取帧率
     * @returns {number}
     */
    getFrameRate() {
        return this._frameRate
    }

    /**
     * 格式化份数
     * @private
     */
    _formatServings() {
        //总份数等于时长处以帧率（向下取整）
        this._servingCount = Math.floor(this.duration / this._frameRate)
        let difference = this.endValue - this.startValue
        //单个份数
        this._servingSize = difference / this._servingCount
    }

    /**
     * 计算当前值
     * @private
     */
    _computeCurrentValue() {
        let currentValue = this.startValue + this._currentServeIndex * this._servingSize
        return currentValue
    }

    /**
     * 开始动画
     * @param duration
     */
    startAnim(duration = this.duration) {
        this.duration = duration
        this.cancelAnim()
        //当前份数位置设置为0
        this._currentServeIndex = 0
        //开始前格式化
        this._formatServings()
        //通知动画开始
        if (this.onStart != null) {
            this.onStart.call()
        }
        //定时动画
        this._intervalTaskId = setInterval(() => {
            //大于总份数（为什么不是大于等于？因为使用0开始的，等于份数的时候刚好是最终值）
            if (this._currentServeIndex > this._servingCount) {
                //结束时值还没到结束值则先通知一次
                if (this._computeCurrentValue() < this.endValue) {
                    if (this.onUpdate != null) {
                        this.onUpdate.call(null, this.startValue + this.endValue)
                    }
                }
                //结束
                if (this.onEnd != null) {
                    this.onEnd.call()
                }
                //取消（结束时取消不需要通知监听者）
                this.cancelAnim(false)
                return
            }
            //更新
            if (this.onUpdate != null) {
                this.onUpdate.call(null, this._computeCurrentValue())
            }
            //更新份数
            this._currentServeIndex++
        }, this._frameRate);
    }

    /**
     * 取消闪烁任务
     */
    cancelAnim(notify = true) {
        // 取消延时任务
        if (this._intervalTaskId != null) {
            clearInterval(this._intervalTaskId);
            this._intervalTaskId = null;
            if (notify) {
                if (this.onCancel != null) {
                    this.onCancel.call()
                }
            }
        }
    }

}

/**
 * 视图显示隐藏动画
 * @author slc
 */
class TimerTask {

    _delayTaskId = null
    _intervalTaskId = null

    _initialDelay = null
    _period = null

    onTaskRun = null
    onTaskCancel = null

    constructor() {
    }

    _notifyTaskRun(initialRun) {
        if (this.onTaskRun != null) {
            this.onTaskRun.call(null, initialRun)
        }
    }

    //开始任务
    startInterval(initialDelay, period) {
        this._initialDelay = initialDelay
        this._period = period
        this.cancelInterval()
        if (this._initialDelay != null) {
            this._delayTaskId = setTimeout(() => {
                this._notifyTaskRun(true)
                this._startIntervalTask()
            }, this._initialDelay);
        }
    }

    //取消任务
    cancelInterval() {
        // 取消延时任务
        if (this._delayTaskId != null) {
            clearTimeout(this._delayTaskId);
            this._delayTaskId = null;
            this._cancelIntervalTask()
            //通知取消
            if (this.onTaskCancel != null) {
                this.onTaskCancel.call()
            }
        }
    }

    //开始定时
    _startIntervalTask() {
        this._cancelIntervalTask()
        if (this._period != null) {
            this._intervalTaskId = setInterval(() => {
                this._notifyTaskRun(false)
            }, this._period);
        }
    }

    //取消定时
    _cancelIntervalTask() {
        // 取消延时任务
        if (this._intervalTaskId != null) {
            clearInterval(this._intervalTaskId);
            this._intervalTaskId = null;
        }
    }

}

class ClickCountProxy {
    _DEF_VALID_INTERVAL = 512;
    _DEF_EXECUTE_COUNT = 5;

    constructor() {
        this.validInterval = 512;
        this.executeCount = 5;
        this.preCallTime = 0;
        this.currentClickCount = 0;
        this.onExecuteListener = null;
    }

    getValidInterval() {
        return this.validInterval;
    }

    setValidInterval(validInterval) {
        this.validInterval = validInterval;
    }

    getExecuteCount() {
        return this.executeCount;
    }

    setExecuteCount(executeCount) {
        this.executeCount = executeCount;
    }

    getOnExecuteListener() {
        return this.onExecuteListener;
    }

    setOnExecuteListener(onExecuteListener) {
        this.onExecuteListener = onExecuteListener;
    }

    clickCall() {
        const currentTime = Date.now();
        if (currentTime - this.preCallTime < this.validInterval) {
            this.currentClickCount++;
            if (this.currentClickCount === this.executeCount) {
                this.currentClickCount = 0;
                if (this.onExecuteListener) {
                    this.onExecuteListener.call(null);
                }
            }
        } else {
            this.currentClickCount = 1;
        }
        this.preCallTime = currentTime;
    }
}

/**
 * 获取视屏大小
 * @param width
 * @param video
 * @returns {{width, video}}
 */
function getVideoSize(width, video) {
    return {
        width: width,
        video: video
    }
}

function getMediaDevices(kind, then) {
    navigator.mediaDevices.enumerateDevices().then((mediaDevices) => {
        const mediaDevicesByKind = []
        mediaDevices.forEach((mediaDevice) => {
            if (mediaDevice.kind === kind) {
                mediaDevicesByKind.push(mediaDevice)
            }
        })
        then.call(null, mediaDevicesByKind)
    });
}

/**
 * 获取视频输入设备
 */
function getVideoInput(then) {
    return getMediaDevices('videoinput', then)
}

/**
 * 获取视频输入设备
 */
function getAudioInput(then) {
    return getMediaDevices('audioinput', then)
}

/**
 * 获取相机流
 * @param video
 * @param success
 * @param error
 */
function getCameraStream(video, success, error) {
    if (navigator.mediaDevices.getUserMedia) {
        //最新的标准API
        navigator.mediaDevices.getUserMedia({
            video: video,
            audio: false
        }).then(success).catch(error);
    } else if (navigator.webkitGetUserMedia) {
        //webkit核心浏览器
        navigator.webkitGetUserMedia({video: video}, success, error)
    } else if (navigator.mozGetUserMedia) {
        //firfox浏览器
        navigator.mozGetUserMedia({video: video}, success, error);
    } else if (navigator.getUserMedia) {
        //旧版API
        navigator.getUserMedia({video: video}, success, error);
    }
}

/**
 * 获取url参数
 * @returns {URLSearchParams}
 */
function getUrlParams() {
    return new URLSearchParams(window.location.search)
}

/**
 * 获取随机字符串
 * @param length
 * @returns {string}
 */
function getSecureRandomString(length = 10) {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    const randomValues = new Uint32Array(length);
    window.crypto.getRandomValues(randomValues);
    let result = '';
    for (let i = 0; i < length; i++) {
        result += chars[randomValues[i] % chars.length];
    }
    return result;
}